﻿using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace System.IO.Win32
{
    internal static class NativeMethods
    {
        public static Runtime.InteropServices.ComTypes.FILETIME ToFileTime(this DateTime dt)
        {
            var fileTimeUtc = dt.ToFileTimeUtc();
            var fileTime = new Runtime.InteropServices.ComTypes.FILETIME();

            fileTime.dwLowDateTime = (int) fileTimeUtc;
            fileTime.dwHighDateTime = (int) (fileTimeUtc >> 32);

            return fileTime;
        }

        public static DateTime ToDateTime(this Runtime.InteropServices.ComTypes.FILETIME filetime)
        {
            return DateTime.FromFileTimeUtc(((long) filetime.dwHighDateTime << 32) + filetime.dwLowDateTime);
        }

        [StructLayout(LayoutKind.Sequential)]
        internal class SECURITY_ATTRIBUTES
        {
            internal int nLength;
            internal IntPtr pSecurityDescriptor;
            internal int bInheritHandle;

        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct WIN32_FIND_DATAW
        {
            public uint dwFileAttributes;
            public Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
            public Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
            public Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
            public uint nFileSizeHigh;
            public uint nFileSizeLow;
            public uint dwReserved0;
            public uint dwReserved1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 520)]
            public string cFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 28)]
            public string cAlternateFileName;
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATAW lpFindFileData);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATAW lpFindFileData);

        [DllImport("kernel32.dll")]
        public static extern bool FindClose(IntPtr hFindFile);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);


        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
        public static extern SafeFileHandle CreateFile(string lpFileName,
            int dwDesiredAccess, 
            FileShare dwShareMode, 
            SECURITY_ATTRIBUTES securityAttrs, 
            FileMode dwCreationDisposition, 
            int dwFlagsAndAttributes, 
            IntPtr hTemplateFile);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DeleteFile([MarshalAs(UnmanagedType.LPTStr)] string lpFileName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool SetFileTime(SafeFileHandle hFile, 
            [In] ref Runtime.InteropServices.ComTypes.FILETIME lpCreationTime, 
            [In] ref Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime, 
            [In] ref Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool SetFileAttributes(string lpFileName, uint dwFileAttributes);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool MoveFile(string src, string dst);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
        public static extern bool ReplaceFile(string replacedFileName, string replacementFileName, string backupFileName, int dwReplaceFlags, IntPtr lpExclude, IntPtr lpReserved);
    }
}